/*
 * code_engine.c
 *
 *  Created on: 2011-7-20
 *      Author: minorityee1984@gmail.com
 *     Purpose: 編解碼實現
 *        Note: 1. 首先添加消息定義(msg_def.h，見“消息體定義步驟1～4”)
 *              2. 實現per-message encode/decode method
 *              3. 在code engine中的switch-case添加相關代碼
 */

#include "code_engine.h"
#include "msg_def.h"
#include "err_def.h"
#include <assert.h>
#include <stdio.h>


/////////////////////////////////////////////
//			code engine facility
/////////////////////////////////////////////

int g_code_endian = 0;	// 0 indicates little-endian

static int is_big_endian();
static void test_endian();

void init_code_engine()
{
	test_endian();
}

int is_big_endian()
{
	int16_t a = 0x0102;
	char *b = (char*)&a;
	if (*b == 0x01)
		return 1;
	return 0;
}

void test_endian()
{
	g_code_endian = is_big_endian();
}


#define __START_CODEING__(MSGTYPE) MSGTYPE* pt = (MSGTYPE*)p

#define __ENCODE_MSG_HEADER__() do {\
	int ret = encode_msg_header(pszBuf, uBufLen, puOffset, &(p->header), MSG_HEADER_SIZE);	\
	pszBuf += *puOffset; \
	if (0 > ret)\
	{ \
		return ret; \
	} \
}while(0)

#define __DECODE_MSG_HEADER__() do {\
	int ret = decode_msg_header(pszBuf, uBufLen, puOffset, &(p->header), MSG_HEADER_SIZE);	\
	pszBuf += *puOffset; \
	if (0 > ret)\
	{ \
		return ret; \
	} \
}while(0)

#define __CHECK_ENCODE_PARAM__() do { \
		assert(NULL != pszBuf); \
		assert(NULL != puOffset); \
		assert(NULL != p); \
}while(0)

#define __CHECK_MSG_PTR__() do { \
		assert(NULL != p); \
		if (NULL == p) \
		{ \
			return; \
		} \
}while(0)

#define __CHECK_DECODE_PARAM__() do { \
		assert(NULL != pszBuf); \
		assert(NULL != puOffset); \
		assert(NULL != p) \
		assert(uBufLen > uSize); \
		/*檢查buff長度是否足夠一個消息*/ \
		if (uSize > uBufLen) \
		{ \
			return E_INCOMPLETE_PACKAGE; \
		} \
}while(0)

#define __ENCODE__(value) \
	ENCODE(pszBuf, *puOffset, pt->value)

#define __DECODE__(value) \
	DECODE(pszBuf, *puOffset, pt->value)

#define __ENCODE_MSG__(MSGTYPE) do {\
		msg_encode_method do_encode = GET_ENCODE_METHOD(MSGTYPE); \
		ret = do_encode(pszBuf, uBufLen, puOffset, &(p->body), uSize);\
}while(0)

#define __DECODE_MSG__(MSGTYPE) do{\
		msg_decode_method do_decode = GET_DECODE_METHOD(MSGTYPE); \
		ret = do_decode(pszBuf, uBufLen, puOffset, &(p->body), uSize);\
}while(0)

/////////////////////////////////////////////
//		per-message encode/decode method
/////////////////////////////////////////////

DECLEAR_MSG_ENCODE(MsgInit)
{
	__CHECK_ENCODE_PARAM__();
	__START_CODEING__(MsgInit);
	__ENCODE__(fill);
	return S_OK;
}

DECLEAR_MSG_DECODE(MsgInit)
{
	__CHECK_DECODE_PARAM__();
	__START_CODEING__(MsgInit);
	__DECODE__(fill);
	return S_OK;
}

DECLEAR_MSG_DUMP(MsgInit)
{
	__CHECK_ENCODE_PARAM__();
	*puOffset = 0;
	*puOffset += snprintf(pszBuf + puOffset, uBufLen - *puOffset, "fill=%d", ((MsgInit*)p)->fill);
}


DECLEAR_MSG_ENCODE(MsgActivateScan)
{
	__CHECK_ENCODE_PARAM__();
	__START_CODEING__(MsgActivateScan);
	__ENCODE__(turnOn);
	return S_OK;
}

DECLEAR_MSG_DECODE(MsgActivateScan)
{
	__CHECK_DECODE_PARAM__();
	__START_CODEING__(MsgActivateScan);
	__DECODE__(turnOn);
	return S_OK;
}

DECLEAR_MSG_DUMP(MsgActivateScan)
{
	__CHECK_ENCODE_PARAM__();
	*puOffset = 0;
	*puOffset += snprintf(pszBuf + puOffset, uBufLen - *puOffset, "turnOn=%d", ((MsgActivateScan*)p)->turnOn);
}


DECLEAR_MSG_ENCODE(MsgActivateRotate)
{
	__CHECK_ENCODE_PARAM__();
	__START_CODEING__(MsgActivateRotate);
	__ENCODE__(turnOn);
	__ENCODE__(degree);
	return S_OK;
}

DECLEAR_MSG_DECODE(MsgActivateRotate)
{
	__CHECK_DECODE_PARAM__();
	__START_CODEING__(MsgActivateRotate);
	__DECODE__(turnOn);
	__DECODE__(degree);
	return S_OK;
}

DECLEAR_MSG_DUMP(MsgActivateRotate)
{
	__CHECK_ENCODE_PARAM__();
	*puOffset = 0;
	*puOffset += snprintf(pszBuf + puOffset, uBufLen - *puOffset, "turnOn=%d", ((MsgActivateRotate*)p)->turnOn);
	if (0 >= (uBufLen - *puOffset))
	{
		return;
	}
	*puOffset += snprintf(pszBuf + puOffset, uBufLen - *puOffset, "degree=%d", ((MsgActivateRotate*)p)->degree);
}

/////////////////////////////////////////////
//			code engine
/////////////////////////////////////////////



int encode_msg_header(Byte *pszBuf, unsigned int uBufLen, unsigned int *puOffset, const MsgHeader *p /*pstMsgHeader*/, unsigned int uSize)
{
	__CHECK_DECODE_PARAM__();
	ENCODE(pszBuf, *puOffset, p->msgID);
	return S_OK;
}
int decode_msg_header(const Byte *pszBuf, unsigned int uBufLen, unsigned int *puOffset, MsgHeader *p /*pstMsgHeader*/, unsigned int uSize)
{
	__CHECK_DECODE_PARAM__();
	DECODE(pszBuf, *puOffset, p->msgID);
	return S_OK;
}


int encode_msg(
				Byte				*pszBuf,
				unsigned int		uBufLen,
				unsigned int		*puOffset,
				const Message		*p /*pstMessage*/,
				unsigned int		uSize)
{
	__CHECK_ENCODE_PARAM__();

	*puOffset = 0;
	int ret = S_OK;

	__ENCODE_MSG_HEADER__();

	switch(p->header.msgID)
	{
	case MSG_CMD_INIT:
		__ENCODE_MSG__(MsgInit);
		break;
	case MSG_CMD_ACTIVATE_SCAN:
		__ENCODE_MSG__(MsgActivateScan);
		break;
	case MSG_CMD_ACTIVATE_ROTATE:
		__ENCODE_MSG__(MsgActivateRotate);
		break;
	default:
		assert(!"E_INVALID_MESSAGE in encode_msg");
		ret = E_INVALID_MESSAGE;
	}
	return ret;
}

int decode_msg(
				const Byte			*pszBuf,
				unsigned int		uBufLen,
				unsigned int		*puOffset,
				Message				*p /*pstMessage*/,
				unsigned int		uSize)
{
	__CHECK_DECODE_PARAM__();

	*puOffset = 0;
	int ret = S_OK;

	__DECODE_MSG_HEADER__();

	switch(p->header.msgID)
	{
	case MSG_CMD_INIT:
		__DECODE_MSG__(MsgInit);
		break;
	case MSG_CMD_ACTIVATE_SCAN:
		__DECODE_MSG__(MsgActivateScan);
		break;
	case MSG_CMD_ACTIVATE_ROTATE:
		__DECODE_MSG__(MsgActivateRotate);
		break;
	default:
		assert(!"E_INVALID_MESSAGE in decode_msg");
		ret = E_INVALID_MESSAGE;
	}
	return ret;
}
